// Copyright (C) 2005-2008 Jae Stutzman (jaebird@gmail.com)
//
// This file is part of Podducer.
//
// Podducer is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Podducer is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Podducer.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.IO;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;
using System.Threading;
using MediaHandler;

namespace Podducer
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class FrmMain : System.Windows.Forms.Form
	{
		private DateTime recStartTime;
		private DateTime pauseStartTime;
		private TimeSpan pauseTimeSpan;

		private RecordController recordController;
		private string publishFilename = string.Empty;

		private delegate void SetVuMeter(int val); 

		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.Label label4;
		private System.Windows.Forms.Label label6;
		private System.Windows.Forms.Label label8;
		private System.Windows.Forms.Label label10;
		private System.Windows.Forms.MainMenu mainMenu1;
		private System.Windows.Forms.Button btnRecord;
		private System.Windows.Forms.Button btnStop;
		private System.Windows.Forms.Button btnPause;
		private System.Windows.Forms.Label lblStatus;
		private System.Windows.Forms.Label lblFilename;
		private System.Windows.Forms.Label lblDuration;
		private System.Windows.Forms.Label lblFilesize;
		private System.Windows.Forms.Label lblBitrate;
		private System.Windows.Forms.Timer timer1;
		private System.Windows.Forms.MenuItem menuItem4;
		private System.Windows.Forms.MenuItem menuAbout;
		private System.Windows.Forms.MenuItem menuConfigure;
		private System.Windows.Forms.MenuItem menuExit;
		private System.Windows.Forms.ProgressBar vuMeter;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.Button btnSetVU;
		private System.Windows.Forms.MenuItem menuPublish;
		private System.Windows.Forms.MenuItem menuFile;
		private System.Windows.Forms.MenuItem menuView;
		private System.Windows.Forms.MenuItem menuOnTop;
		private System.ComponentModel.IContainer components;

		public FrmMain()
		{
			// Required for Windows Form Designer support
			InitializeComponent();

			menuConfigure.Enabled = true;

			btnRecord.Enabled = true;
			btnPause.Enabled = false;
			btnStop.Enabled = false;

			lblStatus.Text = "Stopped";
		}

		public FrmMain(RecordController recordController)
			: this()
		{
			this.recordController = recordController;
			this.recordController.RecordOccured += new ControllerHandler(recordController_RecordOccured);
			this.recordController.PauseOccured += new ControllerHandler(recordController_PauseOccured);
			this.recordController.StopOccured += new ControllerHandler(recordController_StopOccured);
			this.recordController.VuMeasureOccured += new VuMeasureHandler(recordController_VuMeasureOccured);
		}

		private int WM_QUERYENDSESSION = 0x11;
		private bool systemShutdown = false;
		protected override void WndProc(ref System.Windows.Forms.Message m)
		{

			if (m.Msg.Equals(WM_QUERYENDSESSION))
			{
				systemShutdown = true;
			}
			// If this is WM_QUERYENDSESSION, the closing event should be fired in the base WndProc
			base.WndProc(ref m);
		}

		private void FrmMain_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			if (systemShutdown)
			{
				// reset the variable since they may cancel the shutdown
				systemShutdown = false;
				e.Cancel = false;
			}
			else
			{
				e.Cancel = true;
				Hide();
			}
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.btnRecord = new System.Windows.Forms.Button();
			this.btnStop = new System.Windows.Forms.Button();
			this.btnPause = new System.Windows.Forms.Button();
			this.label1 = new System.Windows.Forms.Label();
			this.lblStatus = new System.Windows.Forms.Label();
			this.lblFilename = new System.Windows.Forms.Label();
			this.label4 = new System.Windows.Forms.Label();
			this.lblDuration = new System.Windows.Forms.Label();
			this.label6 = new System.Windows.Forms.Label();
			this.lblFilesize = new System.Windows.Forms.Label();
			this.label8 = new System.Windows.Forms.Label();
			this.lblBitrate = new System.Windows.Forms.Label();
			this.label10 = new System.Windows.Forms.Label();
			this.mainMenu1 = new System.Windows.Forms.MainMenu();
			this.menuFile = new System.Windows.Forms.MenuItem();
			this.menuConfigure = new System.Windows.Forms.MenuItem();
			this.menuItem4 = new System.Windows.Forms.MenuItem();
			this.menuPublish = new System.Windows.Forms.MenuItem();
			this.menuExit = new System.Windows.Forms.MenuItem();
			this.menuView = new System.Windows.Forms.MenuItem();
			this.menuOnTop = new System.Windows.Forms.MenuItem();
			this.menuAbout = new System.Windows.Forms.MenuItem();
			this.timer1 = new System.Windows.Forms.Timer(this.components);
			this.vuMeter = new System.Windows.Forms.ProgressBar();
			this.label2 = new System.Windows.Forms.Label();
			this.btnSetVU = new System.Windows.Forms.Button();
			this.SuspendLayout();
			// 
			// btnRecord
			// 
			this.btnRecord.Location = new System.Drawing.Point(232, 12);
			this.btnRecord.Name = "btnRecord";
			this.btnRecord.Size = new System.Drawing.Size(56, 24);
			this.btnRecord.TabIndex = 0;
			this.btnRecord.Text = "Record";
			this.btnRecord.Click += new System.EventHandler(this.btnRecord_Click);
			// 
			// btnStop
			// 
			this.btnStop.Location = new System.Drawing.Point(232, 76);
			this.btnStop.Name = "btnStop";
			this.btnStop.Size = new System.Drawing.Size(56, 24);
			this.btnStop.TabIndex = 1;
			this.btnStop.Text = "Stop";
			this.btnStop.Click += new System.EventHandler(this.btnStop_Click);
			// 
			// btnPause
			// 
			this.btnPause.Location = new System.Drawing.Point(232, 44);
			this.btnPause.Name = "btnPause";
			this.btnPause.Size = new System.Drawing.Size(56, 24);
			this.btnPause.TabIndex = 2;
			this.btnPause.Text = "Pause";
			this.btnPause.Click += new System.EventHandler(this.btnPause_Click);
			// 
			// label1
			// 
			this.label1.Location = new System.Drawing.Point(4, 4);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(52, 16);
			this.label1.TabIndex = 3;
			this.label1.Text = "Status:";
			// 
			// lblStatus
			// 
			this.lblStatus.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.lblStatus.Location = new System.Drawing.Point(60, 4);
			this.lblStatus.Name = "lblStatus";
			this.lblStatus.Size = new System.Drawing.Size(152, 16);
			this.lblStatus.TabIndex = 4;
			this.lblStatus.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// lblFilename
			// 
			this.lblFilename.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.lblFilename.Location = new System.Drawing.Point(60, 28);
			this.lblFilename.Name = "lblFilename";
			this.lblFilename.Size = new System.Drawing.Size(152, 16);
			this.lblFilename.TabIndex = 6;
			this.lblFilename.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// label4
			// 
			this.label4.Location = new System.Drawing.Point(4, 28);
			this.label4.Name = "label4";
			this.label4.Size = new System.Drawing.Size(52, 16);
			this.label4.TabIndex = 5;
			this.label4.Text = "Filename:";
			// 
			// lblDuration
			// 
			this.lblDuration.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.lblDuration.Location = new System.Drawing.Point(60, 52);
			this.lblDuration.Name = "lblDuration";
			this.lblDuration.Size = new System.Drawing.Size(152, 16);
			this.lblDuration.TabIndex = 8;
			this.lblDuration.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// label6
			// 
			this.label6.Location = new System.Drawing.Point(4, 52);
			this.label6.Name = "label6";
			this.label6.Size = new System.Drawing.Size(52, 16);
			this.label6.TabIndex = 7;
			this.label6.Text = "Duration:";
			// 
			// lblFilesize
			// 
			this.lblFilesize.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.lblFilesize.Location = new System.Drawing.Point(60, 76);
			this.lblFilesize.Name = "lblFilesize";
			this.lblFilesize.Size = new System.Drawing.Size(152, 16);
			this.lblFilesize.TabIndex = 10;
			this.lblFilesize.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// label8
			// 
			this.label8.Location = new System.Drawing.Point(4, 76);
			this.label8.Name = "label8";
			this.label8.Size = new System.Drawing.Size(52, 16);
			this.label8.TabIndex = 9;
			this.label8.Text = "File Size:";
			// 
			// lblBitrate
			// 
			this.lblBitrate.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.lblBitrate.Location = new System.Drawing.Point(60, 100);
			this.lblBitrate.Name = "lblBitrate";
			this.lblBitrate.Size = new System.Drawing.Size(152, 16);
			this.lblBitrate.TabIndex = 12;
			this.lblBitrate.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// label10
			// 
			this.label10.Location = new System.Drawing.Point(4, 100);
			this.label10.Name = "label10";
			this.label10.Size = new System.Drawing.Size(52, 16);
			this.label10.TabIndex = 11;
			this.label10.Text = "Bitrate:";
			// 
			// mainMenu1
			// 
			this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																					  this.menuFile,
																					  this.menuView,
																					  this.menuAbout});
			// 
			// menuFile
			// 
			this.menuFile.Index = 0;
			this.menuFile.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																					 this.menuConfigure,
																					 this.menuItem4,
																					 this.menuPublish,
																					 this.menuExit});
			this.menuFile.Text = "File";
			this.menuFile.Popup += new System.EventHandler(this.menuFile_Popup);
			// 
			// menuConfigure
			// 
			this.menuConfigure.Index = 0;
			this.menuConfigure.Text = "Configure...";
			this.menuConfigure.Click += new System.EventHandler(this.menuConfigure_Click);
			// 
			// menuItem4
			// 
			this.menuItem4.Index = 1;
			this.menuItem4.Text = "-";
			// 
			// menuPublish
			// 
			this.menuPublish.Index = 2;
			this.menuPublish.Text = "Publish";
			this.menuPublish.Click += new System.EventHandler(this.menuPublish_Click);
			// 
			// menuExit
			// 
			this.menuExit.Index = 3;
			this.menuExit.Text = "Exit";
			this.menuExit.Click += new System.EventHandler(this.menuExit_Click);
			// 
			// menuView
			// 
			this.menuView.Index = 1;
			this.menuView.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
																					 this.menuOnTop});
			this.menuView.Text = "View";
			// 
			// menuOnTop
			// 
			this.menuOnTop.Index = 0;
			this.menuOnTop.Text = "Always On Top";
			this.menuOnTop.Click += new System.EventHandler(this.menuOnTop_Click);
			// 
			// menuAbout
			// 
			this.menuAbout.Index = 2;
			this.menuAbout.Text = "About";
			this.menuAbout.Click += new System.EventHandler(this.menuAbout_Click);
			// 
			// timer1
			// 
			this.timer1.Enabled = true;
			this.timer1.Interval = 500;
			this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
			// 
			// vuMeter
			// 
			this.vuMeter.Location = new System.Drawing.Point(60, 124);
			this.vuMeter.Maximum = 50;
			this.vuMeter.Name = "vuMeter";
			this.vuMeter.Size = new System.Drawing.Size(152, 12);
			this.vuMeter.TabIndex = 13;
			// 
			// label2
			// 
			this.label2.Location = new System.Drawing.Point(4, 124);
			this.label2.Name = "label2";
			this.label2.Size = new System.Drawing.Size(52, 16);
			this.label2.TabIndex = 14;
			this.label2.Text = "VU:";
			// 
			// btnSetVU
			// 
			this.btnSetVU.Enabled = false;
			this.btnSetVU.Location = new System.Drawing.Point(232, 116);
			this.btnSetVU.Name = "btnSetVU";
			this.btnSetVU.Size = new System.Drawing.Size(56, 24);
			this.btnSetVU.TabIndex = 15;
			this.btnSetVU.Text = "Set VU";
			this.btnSetVU.Click += new System.EventHandler(this.btnSetVU_Click);
			// 
			// FrmMain
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(296, 147);
			this.Controls.Add(this.btnSetVU);
			this.Controls.Add(this.label2);
			this.Controls.Add(this.vuMeter);
			this.Controls.Add(this.lblBitrate);
			this.Controls.Add(this.label10);
			this.Controls.Add(this.lblFilesize);
			this.Controls.Add(this.label8);
			this.Controls.Add(this.lblDuration);
			this.Controls.Add(this.label6);
			this.Controls.Add(this.lblFilename);
			this.Controls.Add(this.label4);
			this.Controls.Add(this.lblStatus);
			this.Controls.Add(this.label1);
			this.Controls.Add(this.btnPause);
			this.Controls.Add(this.btnStop);
			this.Controls.Add(this.btnRecord);
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
			this.MaximizeBox = false;
			this.Menu = this.mainMenu1;
			this.MinimizeBox = false;
			this.Name = "FrmMain";
			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
			this.Text = "Podducer";
			this.Closing += new System.ComponentModel.CancelEventHandler(this.FrmMain_Closing);
			this.ResumeLayout(false);

		}
		#endregion

		private void btnRecord_Click(object sender, System.EventArgs e)
		{
			if(!recordController.StartRecord())
			{
				MessageBox.Show("Error starting recording, verify encoders are properly installed in Mr. Podder's executable folder");
			}
		}

		private void btnStop_Click(object sender, System.EventArgs e)
		{
			if (MessageBox.Show("Are you sure you want to stop recording?", 
				"Stop Recording", MessageBoxButtons.YesNo) == DialogResult.Yes)
			{
				recordController.StopRecording();
			}
		}

		private void btnPause_Click(object sender, System.EventArgs e)
		{
			//PauseOrResume();
			recordController.PauseOrResume();
		}

		private void menuAbout_Click(object sender, System.EventArgs e)
		{
			// about dialog...
			FrmAbout about = new FrmAbout();
			about.ShowDialog();
		}

		private void timer1_Tick(object sender, System.EventArgs e)
		{
			int KB = 1024;
			int MB = 1024*KB;

			long filesize = 0;

			try
			{
				if ((recordController.Filename != null) && (File.Exists(recordController.Filename )))
				{
					filesize = (new FileInfo(recordController.Filename )).Length;

					if (filesize > MB)
					{
						lblFilesize.Text = string.Format("{0:0.00}", filesize / MB)+ " MB";
					}
					else
					{
						lblFilesize.Text = string.Format("{0:0}", filesize / KB)+ " KB";
					}
				}

				if (recordController.RecordMode == RecordMode.Recording)
				{
					TimeSpan recDurationTimeSpan = DateTime.Now - recStartTime - pauseTimeSpan;
					lblDuration.Text = recDurationTimeSpan.Hours.ToString("00") + ":" + 
						recDurationTimeSpan.Minutes.ToString("00") + ":" + 
						recDurationTimeSpan.Seconds.ToString("00");

					lblBitrate.Text = Math.Round(filesize / (recDurationTimeSpan.TotalSeconds) / 1024).ToString() + " Kbps";
				}
			}
			catch (Exception ex)
			{
			}
		}

		private void menuExit_Click(object sender, System.EventArgs e)
		{
			Application.Exit();
		}

		private void menuConfigure_Click(object sender, System.EventArgs e)
		{
			FrmConfig form = new FrmConfig();

			if (form.ShowDialog() == DialogResult.OK)
			{
				recordController.RefreshConfiguration();
			}
		}

		private void recordController_RecordOccured()
		{
			menuConfigure.Enabled = false;
			btnRecord.Enabled = false;
			btnPause.Enabled = true;
			btnStop.Enabled = true;

			lblStatus.Text = "Recording...";

			pauseTimeSpan = new TimeSpan();
			recStartTime = DateTime.Now;

			lblFilename.Text = Path.GetFileName(recordController.Filename);
		}

		private void recordController_PauseOccured()
		{
			if (recordController.RecordMode == RecordMode.Recording)
			{
				// it is recording
				lblStatus.Text = "Recording...";
				btnPause.Text = "Pause";
				pauseTimeSpan += DateTime.Now - pauseStartTime;
			}
			else if (recordController.RecordMode == RecordMode.Paused)
			{
				// it is paused...
				lblStatus.Text = "Paused";
				btnPause.Text = "Resume";
				pauseStartTime = DateTime.Now;

			}
		}

		private void recordController_StopOccured()
		{
			menuConfigure.Enabled = true;


			btnRecord.Enabled = true;

			btnPause.Enabled = false;
			btnPause.Text = "Pause";

			btnStop.Enabled = false;

			lblStatus.Text = "Stopped";
		}

		private void recordController_VuMeasureOccured(int val)
		{
			if (vuMeter.InvokeRequired)
			{
				vuMeter.Invoke(new SetVuMeter(recordController_VuMeasureOccured), new object[] {val});
			}
			else
			{
				vuMeter.Value = val;
			}
			
		}

		private void btnSetVU_Click(object sender, System.EventArgs e)
		{
		
		}

		FrmCopyAnimate animate;
		private void menuPublish_Click(object sender, System.EventArgs e)
		{
			publishFilename = string.Empty;

			//if there is now file currently to publish
			if (recordController.Filename == string.Empty)
			{
				OpenFileDialog ofd = new OpenFileDialog();
				ofd.InitialDirectory = recordController.DestinationDirectory;
				ofd.Title = "Select File To Publish";
				ofd.Filter = "MP3 Files (*.mp3)|*.mp3|All files (*.*)|*.*";
				if (ofd.ShowDialog() == DialogResult.OK)
				{
					publishFilename = ofd.FileName;
				}
			}
			else
			{
				publishFilename = recordController.Filename;
			}

			if (publishFilename != string.Empty)
			{
				// This option allows us to tag the audio file correctly and ftp
				// it to the webserver...
				FrmTag tagForm = new FrmTag();

				Mp3Tagger tagger = new Mp3Tagger(publishFilename);

				string artist = string.Empty;
				string title = string.Empty;
                string album = string.Empty;
				string comment = string.Empty;
				DateTime publishDate = DateTime.Now;

				tagger.GetInfo(ref artist, ref title, ref album, 
					ref comment, ref publishDate);

				tagForm.FileArtist = artist;
				tagForm.FileTitle = title;
				tagForm.FileAlbum = album;
				tagForm.FileComment = comment;

				if (tagForm.ShowDialog() == DialogResult.OK)
				{
					// set the data, but don't actually write it out yet...
					tagger.SetInfo(tagForm.FileArtist, tagForm.FileTitle, tagForm.FileAlbum, tagForm.FileComment);

					// Queue the task.
					ThreadPool.QueueUserWorkItem(new WaitCallback(PublishProc), tagger);

					animate = new FrmCopyAnimate();
					animate.ShowDialog();
				}
			}
		}

		// This thread procedure performs the task.
		private void PublishProc(object stateInfo) 
		{
			string message = string.Empty;
			bool uploadSuccess = false;

			try
			{

				TaggerBase tagger = stateInfo as TaggerBase;
				if (tagger != null)
				{
					try
					{
						// actually write the file data out...
						tagger.CommitInfo();
					}
					catch (Exception e)
					{
						message = "Tagging Error Occurred";
						throw;
					}

					string host = AppConfigure.GetAppSetting("Host", string.Empty);
					string user = AppConfigure.GetAppSetting("User", string.Empty);
					string password = AppConfigure.GetAppSetting("Password", string.Empty);
					string uploadDirectory = AppConfigure.GetAppSetting("UploadDirectory", string.Empty);

					Publisher publisher = new Publisher(host, user, password, uploadDirectory);
					uploadSuccess = publisher.Upload(publishFilename, out message);
				}
			}
			catch (Exception e)
			{}

			this.Invoke(new OnPublishedDelegate(OnPublished), new object[] {uploadSuccess, message});
		}

		delegate void OnPublishedDelegate(bool success, string message);

		private void OnPublished(bool success, string message)
		{
			animate.Close();

			if (!success)
			{
				MessageBox.Show(message, "Error Transfering", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void menuFile_Popup(object sender, System.EventArgs e)
		{
			if //((recordController.Filename == string.Empty) ||
			   (recordController.RecordMode != RecordMode.Stopped)
			{
				menuPublish.Enabled = false;
			}
			else
			{
				menuPublish.Enabled = true;
			}
		}

		private void menuOnTop_Click(object sender, System.EventArgs e)
		{
			this.TopMost = menuOnTop.Checked = !menuOnTop.Checked;
		}
	}
}
